import random;
from Activity import Activity;

class BlackBoard(object):
    def __init__(self, inputSim):
        self.stgm = inputSim.stgm;
        self.graph = self.stgm.Graph();
        self.inputSim = inputSim;
        self.aStates = inputSim.aStates;
        self.aActs_Time = dict();
        self.aKeys_Time = [];
        self.aOngoingActs = dict();
        self.aNewActsT = [];
    
    def getIndex(self, aAct):
        for i in range(len(self.aStates)): #For each State
            bMatch = True;
            if aAct[0] == self.aStates[i][0]: #If has same Activity name
                if len(aAct[1])!=len(self.aStates[i][1]): #If has Diff # Args
                    bMatch = False;
                for j in range(len(aAct[1])): #For each Arg element
                    if ((aAct[1][j]=="*" and self.aStates[i][1][j]!="*") or
                        (aAct[1][j]!="*" and self.aStates[i][1][j]=="*")):
                        bMatch = False;
                if bMatch==True:
                    return i;
        return -1;
    
    def getMatches(self, aActT0, actT1):
        aMatches = [];
        for i in range(len(aActT0)): #For each Act in t-1
            for j in range(len(aActT0[i].aPersons)): #For each Arg t-1 element
                if aActT0[i].aPersons[j]=="*":
                    continue;
                bMatch = False;
                for k in range(len(actT1[1])): #For each Arg t element
                    if(aActT0[i].aPersons[j] == actT1[1][k]):
                        bMatch = True;
                        break;
                if bMatch==False:
                    break;
            if bMatch==True:
                aMatches.append([i+1, [aActT0[i].sActivity, aActT0[i].aPersons]]);
        return aMatches;
    
    def getMatch(self, actT0, actT1):
        for j in range(len(actT0[1])): #For each Arg t-1 element
            if actT0[1][j]=="*":
                continue;
            bMatch = False;
            for k in range(len(actT1[1])): #For each Arg t element
                if(actT0[1][j] == actT1[1][k]):
                    bMatch = True;
                    break;
            if bMatch==False:
                break;
        return bMatch;
            
    def getNoisyOR(self, aCondProbs):
        aCPT = [];
        nSize = len(aCondProbs);
        for i in range(2**nSize):
            binCPT = bin(i)[2:].zfill(nSize);
            nP = 1;
            for j in range(nSize):
                if binCPT[j]=="1":
                    nP *= (1-aCondProbs[j]);
            aCPT.append(1-nP);
        return aCPT;
    
    def removeAct(self, sActCode):
        #Find Activity Node (by its given Code)
        aRemActs = [];
        print "Activity To Remove:"
        for sKeyT in self.aKeys_Time:
            for actM in self.aActs_Time[sKeyT]:
                if actM.sId.split(".")[0]==sActCode:
                    aRemActs.append(actM);
                    print actM.rootAct.name;
        #Get InitT & EndT Nodes affected by this Activity
        initRemAct = aRemActs[0];
        endRemAct = aRemActs[-1];
        sT0 = initRemAct.rootAct.aTimes[0];
        sT1 = initRemAct.rootAct.aTimes[-1];
        aTailRemActs = self.check_InitEnd_Act(sActCode, sT0, sT1);
        sT0 = endRemAct.rootAct.aTimes[-1];
        aHeadRemActs = [];
        if self.aKeys_Time.index(sT0)+1 < len(self.aKeys_Time):
            sT1 = self.aKeys_Time[self.aKeys_Time.index(sT0)+1];
            aHeadRemActs = self.check_InitEnd_Act(sActCode, sT0, sT1);        
        print "\nNodes at Tail-Act to Remove:";
        for tailAct in aTailRemActs:
            print "   "+tailAct.rootAct.name;
        print "\nNodes at Head-Act to Remove:";
        for headAct in aHeadRemActs:
            print "   "+headAct.rootAct.name;
        #Modify the EndT range of these other Activities Segments
        print "\nChanging Ranges:"
        sT0 = initRemAct.rootAct.aTimes[0];
        for tailAct in aTailRemActs:
            sKeyT = self.aKeys_Time[self.aKeys_Time.index(sT0)+1]; #Get "t+1"
            sCode = tailAct.sId.split(".")[0];
            for actM in self.aActs_Time[sKeyT]:
                if actM.sId==(sCode+"."+sKeyT):
                    s_T0 = tailAct.rootAct.aTimes[0];
                    s_T1 = actM.rootAct.aTimes[-1];
                    print "---Changing range", actM.rootAct.name, "to: ["+s_T0+"-"+s_T1+"]";
        sT0 = endRemAct.rootAct.aTimes[-1];
        for headAct in aHeadRemActs:
            sKeyT = self.aKeys_Time[self.aKeys_Time.index(sT0)+1]; #Get "t+1"
            sCode = headAct.sId.split(".")[0];
            for actM in self.aActs_Time[sKeyT]:
                if actM.sId==(sCode+"."+sKeyT):
                    s_T0 = headAct.rootAct.aTimes[0];
                    s_T1 = actM.rootAct.aTimes[-1];
                    print "---Changing range", actM.rootAct.name, "to: ["+s_T0+"-"+s_T1+"]";
##        #Removing all nodes of Activity Code
##        for remAct in aRemActs:
##            sT = remAct.rootAct.aTimes[0];
##            iRemAct = self.aActs_Time[sT].index(remAct);
##            del self.aActs_Time[sT][iRemAct];
##            if len(self.aActs_Time[sT]==0):
##                del self.aActs_Time[sT];
##                del self.aKeys_Time[self.aKeys_Time.index(sT)];
##            remAct.removeAct();
        
#        #Check if there is NOT other Head nodes (in this InitT)
#        bHeads = False;
#        sTail_T0 = tailRemAct.rootAct.aTimes[0];
#        for actM in self.aActs_Time[sTail_T0]:
#            if not(actM.bCopySegment):
#                bHeads = True;
#                break;
#            print [actM.rootAct.name, actM.bCopySegment];
#        #Check if there is NOT other Tail nodes (in this InitT)
#        bTails = False;
#        sTail_T1 = tailRemAct.rootAct.aTimes[-1];
#        for actM in self.aActs_Time[sTail_T1]:
#            sId = actM.rootAct.sId.split(".")[0];
#            sId_T0 = sId + "." + sTail_T0;
#            if sId!=sActCode and not(self.graph.idndict.has_key(sId_T0)):
#                bTails = True;
#                break;
            
#    def check_Init_Act(self, sActCode, remAct):
#        aRemActs = [];
#        #Check if there is NOT other Head nodes (in this InitT)
#        bHeads = False;
#        sT0 = remAct.rootAct.aTimes[0];
#        for actM in self.aActs_Time[sT0]:
#            if not(actM.bCopySegment):
#                bHeads = True;
#                break;
#        #Check if there is NOT other Tail nodes (in this InitT)
#        bTails = False;
#        sT1 = remAct.rootAct.aTimes[-1];
#        for actM in self.aActs_Time[sT1]:
#            sId = actM.rootAct.sId.split(".")[0];
#            sId_T0 = sId + "." + sT0;
#            if sId!=sActCode and not(self.graph.idndict.has_key(sId_T0)):
#                bTails = True;
#                break;
#        if not(bTails) and not(bHeads):
#            for actM in self.aActs_Time[sT0]:
#                sId = actM.rootAct.sId.split(".")[0];
#                if actM.rootAct.sId!=(sActCode+"."+sT0):
#                    aRemActs.append(actM);
            
    def check_InitEnd_Act(self, sActCode, sT0, sT1):
        #Check if there is NOT other Head nodes (in this InitT/EndT)
        for actM in self.aActs_Time[sT0]:
            if not(actM.bCopySegment):
                return [];
        #Check if there is NOT other Tail nodes (in this InitT/EndT)
        if sT1=="":
            return [];
        for actM in self.aActs_Time[sT1]:
            sId = actM.rootAct.sId.split(".")[0];
            if sId!=sActCode and not(self.graph.idndict.has_key(sId+"."+sT0)):
                return [];
        #If neither Tails nor Heads were found (in this InitT/EndT)
        aRemActs = [];
        for actM in self.aActs_Time[sT0]:
            if actM.rootAct.sId!=(sActCode+"."+sT0):
                aRemActs.append(actM);
        return aRemActs;
                
        
                    
    
    def getProbSeq(self, aActCodes):
        aActNodes = [];
        aEvNodes = [];
        nProbSeq = 1.0;
        #Set Evidence Nodes
        for sKeyT in self.aActs_Time:
            for actM in self.aActs_Time[sKeyT]:
                for childN in actM.aChildNodes:
                    self.graph.addobs(childN, True);
                    aEvNodes.append(childN.sId);
        #Get Act Nodes
        for actCode in aActCodes:
            if not(self.graph.idndict.has_key(actCode)):
                print "Activity " + actCode + " was Not found.";
                continue;
            aActNodes.append(self.graph.idndict[actCode]);
        #Get Probability of Sequence
        for actM in aActNodes:
            print self.graph.postprob([actM])[0];
            nProbSeq *= self.graph.postprob([actM])[0];
            self.graph.addobs(actM, True);
        for actM in aActNodes:
            self.graph.removeObs(actM);
#        for i in range(len(aEvCodes)):
#            if not(self.graph.idndict.has_key(aEvCodes[i])):
#                print "Evidence " + aEvCodes[i] + " was Not found.";
#                continue;
#            evCode = self.graph.idndict[aEvCodes[i]];
#            self.graph.addobs(evCode, aEvVals[i]);
        print "aActCodes:", aActCodes;
        print "aEvNodes:", aEvNodes;
#        print aEvCodes;
#        print aEvVals;
        print "Posts:", self.graph.postprob(aActNodes);
        return nProbSeq;
    
    def getMaxProbSeq(self, aActSeqs):
        aProbSeqs = [];
        for actSeq in aActSeqs:
            nProbSeq = self.getProbSeq(actSeq);
            aProbSeqs.append(nProbSeq);
        print aProbSeqs;
        nMaxP = max(aProbSeqs);
        iMaxP = aProbSeqs.index(nMaxP);
        return [iMaxP, nMaxP];
            
    
    def getSegmentAct(self, actModel, nInitT, nEndT):
        nInitT = int(nInitT); nEndT = int(nEndT);
        #Activity:
        newAct = self.createActNode(None, actModel.rootAct, nInitT, nEndT, bRoot=True);
        #Create SubActivities:
        for childNode in actModel.aChildNodes:
            #SubActivity:
            newAct = self.createActNode(newAct, childNode, nInitT, nEndT, bRoot=False);
        print "---Created Segment Activity Node:";
        self.inputSim.printActNode(newAct);
        return newAct;
    
    def createActNode(self, actModel, actNode, nInitT, nEndT, bRoot=False):
        sActName = actNode.actName;
        sId = actNode.sId.split(".")[0] + "." + str(nEndT);
        aObjects = list(actNode.aObjects); #Each corresponds to their respective time in aObjectTimes
        aObjectTypes = list(actNode.aObjectTypes);
        if bRoot:
            aObjectTimes = [];
            aSubjects = [actNode.aSubjects[0]];
            for i in range(len(actNode.aObjectTimes)):
                aObjT = actNode.aObjectTimes[i];
                aObjectTimes.append(list(aObjT));
                nObjInit = int(aObjT[0].replace("+",""));
                nObjEnd = int(aObjT[1].replace("+",""));
                if nEndT>=nObjInit and nEndT<=nObjEnd:
                    aSubjects.append(aObjects[i]);
        else:
            aSubjects = list(actNode.aSubjects);
            aObjectTimes = list(actNode.aObjectTimes);
        aTimes = list(actNode.aTimes);
        aTimes[0] = str(nInitT);
        aTimes[-1] = str(nEndT);
        sParentsId = [];
        if bRoot==False:
            for parentId in actNode.sParentsId:
                pId = parentId.split(".")[0] + "." + str(nEndT);
                sParentsId.append(pId);
        aScores = list(actNode.aScores);
        sLocation = actNode.location;
        #Add the Activity or Sub-Activity
        if bRoot:
            actModel = Activity(self.stgm, sActName, aSubjects, nEndT, sId, True);
        actModel.makeXmlNode(sId, sActName, aSubjects, aObjects, aObjectTypes, aObjectTimes, aTimes, 
                             sParentsId, aScores, sLocation, bRoot);
        return actModel;
    
    def addActCollisions(self, actModel, bAddTailSgms=True, bAddHeadSgms=True):
        aTimePts = []; #TimePoints to add Segments
        iAct = self.aKeys_Time.index(str(actModel.nTime)); #Index of Activity in TimeLine
        nInitT = int(actModel.rootAct.aTimes[0]); #Init Time of this Activity
        nEndT = int(self.aKeys_Time[iAct]);
        #Add TimePoints for this Action Segment
        for i in range(iAct+1): #Move from iAct Backwards (up to nInitT)  
            #Note: It also Checks the Init of OtherActs in same Time-Step as this Act
            nEndAct = int(self.aKeys_Time[iAct-i]); #End Time in Each Segment Activity
            if (nEndAct <= nInitT): #If they are NOT overlapping on each other, then NO collision exists
                break;
            for actM in self.aActs_Time[str(nEndAct)]:
                if (nEndAct > nInitT) and (nEndAct < nEndT) and not(nEndAct in aTimePts): 
                    aTimePts.append(nEndAct); #Add Segment's (End) Time Point
                nInitActT = int(actM.rootAct.aTimes[0]);
                if (nInitActT > nInitT) and not(nInitActT in aTimePts):
                    aTimePts.append(nInitActT); #Add Segment's (Init) Time Point
        #Add Collision Segments (from TimePoints Obtained)
        print "-----Adding Segments:---------"
        aTimePts.sort();
        print "aTimePts:", aTimePts;
        if len(aTimePts)>0: #From InitAct to Pt[0]
            nEndPt = aTimePts[0];
            print [nInitT, nEndPt];
            segmentAct = self.getSegmentAct(actModel, nInitT, nEndPt); #Add copy of this node
            self.addActToBB(segmentAct);
        for i in range(len(aTimePts)-1): #From Pt[i] to Pt[i+1] (i>=1)
            nInitPt = aTimePts[i];
            nEndPt = aTimePts[i+1];
            print [nInitPt, nEndPt];
            segmentAct = self.getSegmentAct(actModel, nInitPt, nEndPt); #Add copy of this node
            self.addActToBB(segmentAct);
        self.addFurtherActCollisions(actModel, bAddTailSgms, bAddHeadSgms);
        if len(aTimePts)>0:
            actModel.changeInitT(aTimePts[-1]);
    
    def addFurtherActCollisions(self, actModel, bAddTailSgms=True, bAddHeadSgms=True):
        #Check Further Collisions on Other Activity Nodes (caused by this Activity)
        #---Collect all those Activity Nodes (Collided Activites)---
        aOtherActs_EndP, aOtherActs_InitP = [], [];
        aSgm_EndP, aSgm_InitP = [], [];
        aNames_EndP, aNames_InitP = [], [];
        iAct = self.aKeys_Time.index(str(actModel.nTime)); #Index of Activity in TimeLine
        nInitT = int(actModel.rootAct.aTimes[0]); #Init Time of this Activity
        #Looking for Collisions on Tail Node Activity
        for i in range(len(self.aKeys_Time[:iAct])+1): #Move from HeadAct (iAct) Backwards (up to TailAct+1)
            if (int(self.aKeys_Time[iAct-i]) <= nInitT): break; #If reached TailAct, then Break
            for actM in self.aActs_Time[self.aKeys_Time[iAct-i]]:
                nOtherActT0 = int(actM.rootAct.aTimes[0]); 
                if (nOtherActT0 < nInitT):
                    aOtherActs_InitP.append(actM);
                    aSgm_InitP.append(str(nOtherActT0)+"-"+str(nInitT));
                    aNames_InitP.append(actM.rootAct.name);
        #Looking for Collisions on Head Node Activity & (Rest of) Collisions on Tail Node Activity
        #(Check all Segments from iAct+1 [every further segment must End in iAct+1])
        if iAct+1 < len(self.aKeys_Time): #If iAct+1 exists
            for actM in self.aActs_Time[self.aKeys_Time[iAct+1]]: #For each Act in iAct+1
                nOtherActT0 = int(actM.rootAct.aTimes[0]);
                if (nOtherActT0 < actModel.nTime): #Store collisions on Head Act
                    aOtherActs_EndP.append(actM);
                    aSgm_EndP.append(str(nOtherActT0)+"-"+str(actModel.nTime));
                    aNames_EndP.append(actM.rootAct.name);
                if (nOtherActT0 < nInitT): #Store collisions on Tail Act
                    aOtherActs_InitP.append(actM);
                    aSgm_InitP.append(str(nOtherActT0)+"-"+str(nInitT));
                    aNames_InitP.append(actM.rootAct.name);
        #Add Further Collision Segments (from Collided Activities obtained)
        if bAddTailSgms:
            for otherAct_InitP in aOtherActs_InitP:
                nOtherActT0 = int(otherAct_InitP.rootAct.aTimes[0]);
                segmentAct = self.getSegmentAct(otherAct_InitP, nOtherActT0, nInitT); #Add copy of this node
                self.addActToBB(segmentAct); #Add it to the TimeLine
                otherAct_InitP.changeInitT(nInitT); #Update InitT of Segments (that collided with TailAct)
        if bAddHeadSgms:
            for otherAct_EndP in aOtherActs_EndP:
                nOtherActT0 = int(otherAct_EndP.rootAct.aTimes[0]);
                if (nOtherActT0 < nInitT and bAddTailSgms): nOtherActT0 = nInitT; #Fix Init Time of NEW segment to TailAct (if was before that & TailAct was added)
                segmentAct = self.getSegmentAct(otherAct_EndP, nOtherActT0, actModel.nTime); #Add copy of this node
                self.addActToBB(segmentAct); #Add it to the TimeLine
                otherAct_EndP.changeInitT(actModel.nTime); #Update InitT of Segments (that collided with HeadAct)
        #Print Results
#        print "---Further Collisions from:", actModel.rootAct.name;
#        print "END-Pt Collisions";
#        print "aOtherActs_EndP (Colliding With These Activities):", aNames_EndP;
#        print "aSgm_EndP (FULL Segment TimePt):", aSgm_EndP;
#        print "bAddTailSgms (Tail Collisions Added?):", bAddTailSgms;
#        print "---"
#        print "INIT-Pt Collisions";
#        print "aOtherActs_InitP (Colliding With These Activities):", aNames_InitP;
#        print "aSgm_InitP (FULL Segment TimePt):", aSgm_InitP;
#        print "bAddHeadSgms (Tail Collisions Added?):", bAddHeadSgms;
#        print "";
            
    
    def addActToBB(self, actModel):
        sT = str(actModel.nTime);
        self.aNewActsT.append(sT);
        if self.aActs_Time.has_key(sT): #If Existing Time Point
            self.aActs_Time[sT].append(actModel);
        else: #If NEW Time Point
            self.aActs_Time[sT] = [actModel];
            self.addKeyTime(sT);
            
    def checkOngoingAct(self, actModel):
        bIsOngoing = actModel.rootAct.aTimes[-1].endswith("+");
        bWasAdded = self.aOngoingActs.has_key(actModel.sId.split(".")[0]);
        print "[bIsOngoing, bWasAdded]:", [bIsOngoing, bWasAdded];
        if bIsOngoing and bWasAdded:
            self.updateOngoingAct(actModel);
        elif bIsOngoing and not(bWasAdded):
            self.addOngoingAct(actModel);
        elif not(bIsOngoing) and bWasAdded:
            self.finishOngoingAct(actModel);
        else:
            return False;
        return True;
        
    def updateOngoingAct(self, ongoingAct):
        #Try again to Add this ongoingAct (if was Unable bo be added before).
        iKey = ongoingAct.sId.split(".")[0];
        if self.aOngoingActs[iKey][1]==False: #If hasn't been Added yet, then
            self.addOngoingAct(ongoingAct); #Try adding it again
            return;
        #Update this ongoingAct (by adding another copy in latest Time-Step)
        #Note: We assume nEndT is always latest time step (regardless of value given in XML [due to "+"])
        self.aOngoingActs[iKey][0] = ongoingAct;
        nInitT = self.aOngoingActs[iKey][2]; #Latest Time Added before
        nEndT = int(self.aKeys_Time[-1]) if len(self.aKeys_Time)>0 else -1;
        if nInitT < nEndT:
            self.aOngoingActs[iKey][2] = nEndT;
            segmentAct = self.getSegmentAct(ongoingAct, nInitT, nEndT); #Add copy of this node
            self.addActToBB(segmentAct);
            self.addActCollisions(segmentAct, bAddTailSgms=True, bAddHeadSgms=False);
    
    def addOngoingAct(self, ongoingAct):
        nEndT = int(self.aKeys_Time[-1]) if len(self.aKeys_Time)>0 else -1;
        bAbleToAdd = len(self.aKeys_Time)>0; #and ongoingAct.nTime<nEndT;
        self.aOngoingActs[ongoingAct.sId.split(".")[0]] = [ongoingAct, bAbleToAdd, nEndT];
        print "self.aOngoingActs", self.aOngoingActs;
        if bAbleToAdd:
            nInitT = int(ongoingAct.rootAct.aTimes[0]);
            segmentAct = self.getSegmentAct(ongoingAct, nInitT, nEndT); #Add copy of this node
            self.addActToBB(segmentAct);
            self.addActCollisions(segmentAct, bAddTailSgms=True, bAddHeadSgms=False);
    
    def finishOngoingAct(self, ongoingAct):
        #Try again to Add this ongoingAct (if was Unable bo be added before).
        iKey = ongoingAct.sId.split(".")[0];
        if self.aOngoingActs[iKey][1]==False: #If hasn't been Added yet, then
            self.addOngoingAct(ongoingAct); #Try adding it again
        #Finish this ongoingAct (by adding the Last copy in End Time-Step given)
        nOngoingEndT = self.aOngoingActs[iKey][2];
        nInitT = nOngoingEndT if nOngoingEndT!=-1 else int(ongoingAct.rootAct.aTimes[0]); #Latest Time Added before
        nEndT = int(ongoingAct.rootAct.aTimes[-1]);
        if nInitT < nEndT:
            segmentAct = self.getSegmentAct(ongoingAct, nInitT, nEndT); #Add copy of this node
            self.addActToBB(segmentAct);
            self.addActCollisions(segmentAct, bAddTailSgms=False, bAddHeadSgms=True);
        del self.aOngoingActs[ongoingAct.sId.split(".")[0]];              
    
    def getNextActsT(self):
        for i in range(len(self.aKeys_Time)-1):
            sKeyT0 = self.aKeys_Time[i];
            sKeyT1 = self.aKeys_Time[i+1];
            if sKeyT0 in self.aNewActsT and not(sKeyT1) in self.aNewActsT:
                self.aNewActsT.append(sKeyT1);
        self.aNewActsT.sort();
    
    def addXmlActs_ToBB(self, sXmlFile=""):
        #Read XML file to get Activities
        self.inputSim.makeXmlActivities(sXmlFile);
        #Insert all XML Activities into the timeline of HMM BB
        self.aNewActsT = [];
        for i in range(len(self.inputSim.aActivities)): #For all XML Activities
            if self.checkOngoingAct(self.inputSim.aActivities[i]): 
                continue;
            self.addActToBB(self.inputSim.aActivities[i]);
            self.addActCollisions(self.inputSim.aActivities[i]);
        #Add & Link All Activities to the Graph
        print "aKeys_Time:", self.aKeys_Time;
        self.getNextActsT();
        print "aNewActsT:", self.aNewActsT;
        for sK in self.aNewActsT:
            self.addNodesToGraph(sK);
            self.linkActivities(sK);
        self.graph.setup();
            
    def addKeyTime(self, sTime):
        for i in range(1,len(self.aKeys_Time)+1):
            if int(sTime) > int(self.aKeys_Time[-i]):                
                k = len(self.aKeys_Time)-i;
                self.aKeys_Time.insert(k+1, sTime);
                return;
        #Else (if sTime < self.aKeys_Time[0])
        self.aKeys_Time.insert(0, sTime);
    
    def addNodesToGraph(self, sTime):
        for i in range(len(self.aActs_Time[sTime])): #For each Act[t]
            aActT1 = self.aActs_Time[sTime][i];
            sAct1 = aActT1.getKeyTexts();
            if self.inputSim.bReadXML==True:
#                print "Adding:", aActT1.sId;
                aActT1.makeXmlGraph(self.graph);
            else:
                nPrior = self.inputSim.aPriors[self.getIndex(sAct1)];
                aActT1.makeRndGraph(self.graph, nPrior);
            
    def linkActivities(self, sTime):
        for i in range(len(self.aActs_Time[sTime])): #For each Act[t]
            aActT1 = self.aActs_Time[sTime][i];
            sAct1 = aActT1.getKeyTexts();
            sPastTime = self.getPastKey(sTime);
            bPrior = (True if sPastTime==None else False);
            [aActs, aProbs] = self.getPastLinks(sPastTime, sAct1, bPrior);
#            [aActsM, aProbsM] = self.getMarkovLinks(sTime, sAct1);
#            if len(aActsM)>0:
#                if len(aActs)==0:
#                    aActs = aActsM;
#                    aProbs = aProbsM;                   
#                else:
#                    aActs.extend(aActsM);
#                    aProbs.extend(aProbsM);
            if len(aActs)>1:
                aProbs = self.getNoisyOR(aProbs);
            self.graph.addnode(aActT1.rootAct, aActs, aProbs);
            
    def getPastKey(self, sTime):
        iKey = self.aKeys_Time.index(sTime)-1;
        if iKey<0:
            return None;
        else:
            return self.aKeys_Time[iKey];

    def getPastLinks(self, sT0, sAct1, bPrior=False):
        aActs, aProbs = [], [];
        nIndexA1 = self.getIndex(sAct1);
        if bPrior:
            #Send a Prior
            aProbs.append(self.inputSim.aPriors[nIndexA1]);
            return [aActs, aProbs];
        for j in range(len(self.aActs_Time[sT0])): #For each Act[t-1]
            actT0 = self.aActs_Time[sT0][j];
            sAct0 = actT0.getKeyTexts();
            nIndexA0 = self.getIndex(sAct0);
            if self.getMatch(sAct0, sAct1):
                #Send a Transition
                aProbs.append(self.inputSim.aTrans[nIndexA0][nIndexA1]);
                aActs.append(actT0.rootAct);
        if aActs==[]:
            #Send a Prior
            aProbs.append(self.inputSim.aPriors[nIndexA1]);
        return [aActs, aProbs];
    
    def getMarkovLinks(self, sT0, sAct1):
        aActs, aProbs = [], [];
        nIndexA1 = self.getIndex(sAct1);
        for j in range(len(self.aActs_Time[sT0])): #For each Act[t]
            actT0 = self.aActs_Time[sT0][j];
            sAct0 = actT0.getKeyTexts();
            if sAct0==sAct1:
                continue;
            nIndexA0 = self.getIndex(sAct0);
            if self.getMatch(sAct0, sAct1) and self.getMatch(sAct1, sAct0):
                #Send Markov Correlation
                aProbs.append(self.inputSim.aMarkovM[nIndexA0][nIndexA1]);
                aActs.append(actT0.rootAct);
        return [aActs, aProbs];
                
                
                
                    